﻿using Modbus.Device;
using SqlSugar.Extensions;
using System.Diagnostics;
using System.IO.Ports;
using System.Runtime.InteropServices.JavaScript;
using Vanara;
using WinFormium;
using WinFormium.Forms;

namespace TestPressure
{
    internal class IndexForm : Formium
    {
        #region
        /// <summary>串口字典
        ///  串口地址为Key
        /// </summary>
        private Dictionary<string, SerialPort>? serialPortDic = new Dictionary<string, SerialPort> { };

        /// <summary>串口字典
        /// 设备编号为Key
        /// </summary>
        private Dictionary<string, SerialPort>? deviceSerialPortDic = new Dictionary<string, SerialPort> { };

        /// <summary>点位字典
        /// 
        /// </summary>
        private Dictionary<string, Dictionary<string, object>>? masterDic = new Dictionary<string, Dictionary<string, object>> { };

        /// <summary>界面点位字典
        /// 
        /// </summary>
        private Dictionary<string, string>? frormPointDic = new Dictionary<string, string> { };

        /// <summary>语音串口
        /// 
        /// </summary>
        private SerialPort? voiceSerialPort;

        /// <summary>语音设备地址
        /// 
        /// </summary>
        private string? voiceDeviceAddress;

        /// <summary>语音播报状态
        /// 
        /// </summary>
        private bool voiceBroadcastState = false;

        /// <summary>采集计时器
        /// 
        /// </summary>
        private System.Timers.Timer MCollectTimer;

        #endregion

        #region 自定义方法

        /// <summary>配置
        /// 
        /// </summary>
        public void setup()
        {
            this.MCollectTimer = new System.Timers.Timer();
            this.MCollectTimer.Interval = 1100;
            this.MCollectTimer.AutoReset = true;//是否重复执行
            this.MCollectTimer.Elapsed += MReadRegister;
            RegisterJavaScriptMessagHandler("StartCollect", args =>
            {
                this.MCollectTimer.Start();
            });
        }
        protected override void OnClosed()
        {
            Process.GetCurrentProcess().Kill();
        }
        /// <summary>设备列表
        /// 
        /// </summary>
        public void loadDeviceList()
        {
            List<Device> list = SqlSugarHelper.Inquireable<Device>(null);

            foreach (Device item in list)
            {
                Log.Debug("开始联接端口" + item.port_address);
                string deviceNumber = item.device_number.ToString();
                string portName = item.port_address; // 串口地址
                int baudRate = item.baudrate;   // 波特率
                var dataBits = 8;      // 数据位
                var stopBits = StopBits.One; // 停止位
                var parity = Parity.None;    // 校验位
                SerialPort serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                if (!serialPortDic.ContainsKey(item.port_address))
                {
                    try
                    {
                        serialPort.Open();
                        if (serialPort.IsOpen)
                        {
                            Log.Info(portName + "：端口连接成功");
                            deviceSerialPortDic[item.device_number.ToString()] = serialPort;
                            serialPortDic[item.port_address] = serialPort;
                        }
                        else
                        {
                            Log.Info(portName + "：端口连接失败");
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Error(portName + "连接异常：" + ex.Message);
                    }
                }
                else
                {
                    deviceSerialPortDic[deviceNumber] = serialPortDic[item.port_address];
                    Log.Info(portName + "端口连接成功");
                }
            }

            Task.Run(() =>
            {
                loadDevicePointList();
            });
        }

        /// <summary>设备点位列表
        /// 
        /// </summary>
        public void loadDevicePointList()
        {
            List<DevicePoint> list = SqlSugarHelper.Inquireable<DevicePoint>(null);
            foreach (DevicePoint item in list)
            {
                if (deviceSerialPortDic.ContainsKey(item.device_number.ToString()))
                {
                    Dictionary<string, Object> obj = new Dictionary<string, Object> { };
                    obj["slaveAddress"] = item.device_address;
                    obj["startAddress"] = item.point_address;
                    obj["numberOfPoints"] = 1;
                    obj["rangeMin"] = item.range_min;
                    obj["rangeMax"] = item.range_max;
                    obj["signalMin"] = item.out_min;
                    obj["signalMax"] = item.out_max;
                    obj["pointName"] = item.point_name;
                    obj["devicePoint"] = item;
                    SerialPort serialPort = deviceSerialPortDic[item.device_number.ToString()];
                    ModbusSerialMaster master = ModbusSerialMaster.CreateRtu(serialPort);
                    master.Transport.WriteTimeout = 1000;
                    master.Transport.ReadTimeout = 1000;
                    obj["master"] = master;
                    obj["serialPort"] = serialPort;
                    obj["deviceAddress"] = item.device_address;
                    masterDic[item.point_number.ToString()] = obj;
                }
                else
                {
                    string log = string.Format("【{0}】连接异常,无法读取【{1}】", item.device_name, item.point_name);
                    Log.Error(log);
                }
            }

            Task.Run(() =>
            {
                loadFormPointList();
            });
        }

        /// <summary>界面点位列表
        /// 
        /// </summary>
        public void loadFormPointList()
        {
            List<FormPoint> list = SqlSugarHelper.Inquireable<FormPoint>(null);
            foreach (FormPoint item in list)
            {
                frormPointDic[item.form_point_name] = item.device_point_number.ToString();
            }

            Task.Run(() =>
            {
                SetupVoice();
            });

        }

        /// <summary>设置语音
        /// 
        /// </summary>
        private void SetupVoice()
        {
            string key = "voice";

            if (frormPointDic.ContainsKey(key))
            {
                string pointNumber = frormPointDic[key];
                if (masterDic.ContainsKey(pointNumber))
                {
                    Dictionary<string, object> dic = masterDic[pointNumber];
                    voiceSerialPort = (SerialPort)dic["serialPort"];
                    voiceDeviceAddress = dic["deviceAddress"].ToString();
                    int address = voiceDeviceAddress.ObjToInt();
                    voiceDeviceAddress = address.ToString("00");
                    voiceSerialPort.DataReceived += new SerialDataReceivedEventHandler(receivedData);//接收数据事件
                    voiceSerialPort.ReadTimeout = 3;
                    try
                    {
                        Byte[] strbyte = Tool.HexStringToBytes("CCDDAA");
                        voiceSerialPort.Write(strbyte, 0, strbyte.Length);//发送数据
                    }
                    catch (Exception ex)
                    {
                        Log.Error("语音模块联接指令下发异常：" + ex.Message);
                    }
                }
                else
                {
                    Log.Debug("语音master未创建");
                }
            }
        }

        /// <summary>收到串口回复
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void receivedData(object sender, SerialDataReceivedEventArgs e)//接收数据
        {
            SerialPort serialPort = (SerialPort)sender;

            int len = serialPort.BytesToRead;//获取可以读取的字节数

            byte[] buff = new byte[len];//创建缓存数据数组

            try
            {
                serialPort.Read(buff, 0, len);//把数据读取到buff数组

                string back = BitConverter.ToString(buff, 0, buff.Length).Replace("-", "");
                if (back.Contains("CCDDAA"))
                {
                    Log.Info("语音模块已联接");
                    voiceBroadcastState = true;
                    if (voiceBroadcastState)
                    {
                        Broadcast("开机，请建立工程");
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error("读取串口回复数据异常：" + ex.Message);
            }
        }

        /// <summary>播报
        /// 
        /// </summary>
        /// <param name="msg"></param>
        private void Broadcast(string content)
        {
            Log.Debug("语音播报：" + content);

            string lengthString = Tool.StringByteLength(content).ToString("X");
            if (lengthString.Length < 2)
            {
                lengthString = "0" + lengthString;
            }
            Log.Info(string.Format("数据长度:{0}", lengthString));
            string hexContent = Tool.GetHexFromChs(content);
            Log.Info(string.Format("数据内容:{0}", hexContent));

            string command = voiceDeviceAddress + "1000000000" + lengthString + hexContent;
            Log.Info(string.Format("指令:{0}", command));

            string crc = Tool.CRCForModbus(command);
            command = command + crc;
            if (voiceSerialPort != null)
            {
                if (voiceSerialPort.IsOpen)
                {
                    Byte[] strbyte = Tool.HexStringToBytes(command);
                    voiceSerialPort.Write(strbyte, 0, strbyte.Length);//发送数据
                    Log.Info(string.Format("下发播报指令：{0}", command));
                }
                else
                {
                    Log.Info("联接错误，无法下发播报指令");
                }
            }
        }
        /// <summary>读取寄存器
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MReadRegister(object sender, System.Timers.ElapsedEventArgs e)
        {

            DateTime now = DateTime.Now;

            int sleep = 130;
            
            bool[] res = ReadCoilsAsync("MFan", 1);
            if (res != null)
            {
                Log.Debug("主风扇状态：" + res[0]);
            }
            else
            {
                Log.Error("主机箱风扇获取失败");
            }

            Thread.Sleep(sleep);
            Dictionary<string, object> back = ReadInputRegistersAsync("MTemplature");
           
            if (back != null)
            {

                ushort[] shorts = (ushort[])back["data"];
                DevicePoint point = (DevicePoint)back["devicePoint"];
                float temperature = (Tool.ConvertUshort(shorts[0]) / 10.0f);
                if (temperature > point.alarm_hight)
                {
                    string data = string.Format("mainTemplature({0},1)", temperature);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】超过限高阈值【{2}】", point.point_name, temperature, point.alarm_hight);
                    Log.Debug(msg);
                }
                else
                {
                    string data = string.Format("mainTemplature({0},0)", temperature);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】", point.point_name, temperature);
                    Log.Debug(msg);
                }
            }
            else
            {
                Log.Error("主机箱温度获取失败");
            }

            Thread.Sleep(sleep);
            back = ReadHoldingRegistersAsync("MPressure");
            if (back != null)
            {
                ushort[] shorts = (ushort[])back["data"];

                DevicePoint point = (DevicePoint)back["devicePoint"];

                float outMax = point.out_max;

                float outMin = point.out_min;

                float rangeMax = point.range_max;

                float rangeMin = point.range_min;

                double pressure = (shorts[0] - outMin) / (outMax - outMin);
                pressure = Math.Round(pressure * (rangeMax - rangeMin) + rangeMin, 1);
                if (pressure > point.alarm_hight)
                {
                    string data = string.Format("mainPressure({0},1)", pressure);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】超过限高阈值【{2}】", point.point_name, pressure, point.alarm_hight);
                    Log.Debug(msg);
                }
                else if (pressure < point.alarm_low)
                {
                    string data = string.Format("mainPressure({0},1)", pressure);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】低于最低阈值【{2}】", point.point_name, pressure, point.alarm_low);
                    Log.Debug(msg);
                }
                else
                {
                    string data = string.Format("mainPressure({0},0)", pressure);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】", point.point_name, pressure);
                    Log.Debug(msg);

                }
            }
            else
            {
                Log.Error("主压力获取失败");
            }

            Thread.Sleep(sleep);
            res = ReadCoilsAsync("RFan", 2);
            if (res != null)
            {
                Log.Debug(string.Format("远端风扇：【{0}】 采集标志：【{1}】", res[0], res[1]));
            }
            else
            {
                Log.Error("远端机箱风扇获取失败");
            }
            
            Thread.Sleep(sleep);
            back = ReadInputRegistersAsync("RTemplature");
            if (back != null)
            {
                ushort[] shorts = (ushort[])back["data"];
                DevicePoint point = (DevicePoint)back["devicePoint"];
                float temperature = (Tool.ConvertUshort(shorts[0]) / 10.0f);
                if (temperature > point.alarm_hight)
                {
                    string data = string.Format("remoteTemplature({0},1)", temperature);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】超过限高阈值【{2}】", point.point_name, temperature, point.alarm_hight);
                    Log.Debug(msg);
                }
                else
                {
                    string data = string.Format("remoteTemplature({0},0)", temperature);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】", point.point_name, temperature);
                    Log.Debug(msg);
                }
            }
            else
            {
                Log.Error("远机箱温度获取失败");
            }
            Thread.Sleep(sleep);
            back = ReadHoldingRegistersAsync("RPressure");
            if (back != null)
            {

                ushort[] shorts = (ushort[])back["data"];

                DevicePoint point = (DevicePoint)back["devicePoint"];

                float outMax = point.out_max;

                float outMin = point.out_min;

                float rangeMax = point.range_max;

                float rangeMin = point.range_min;

                double pressure = (shorts[0] - outMin) / (outMax - outMin);
                pressure = Math.Round(pressure * (rangeMax - rangeMin) + rangeMin, 1);

                if (pressure > point.alarm_hight)
                {
                    string data = string.Format("remotePressure({0},1)", pressure);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】超过限高阈值【{2}】", point.point_name, pressure, point.alarm_hight);
                    Log.Debug(msg);
                }
                else if (pressure < point.alarm_low)
                {
                    string data = string.Format("remotePressure({0},1)", pressure);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】低于最低阈值【{2}】", point.point_name, pressure, point.alarm_hight);
                    Log.Debug(msg);
                }
                else
                {
                    string data = string.Format("remotePressure({0},0)", pressure);
                    EvaluateJavaScriptAsync(data);
                    string msg = string.Format("【{0}:】【{1}】", point.point_name, pressure);
                    Log.Debug(msg);
                }

            }
            else
            {
                Log.Error("远压力获取失败");
            }
        }

        private bool[] ReadCoilsAsync(string key, int count)
        {

            if (frormPointDic.ContainsKey(key))
            {
                string pointNumber = frormPointDic[key];


                if (masterDic.ContainsKey(pointNumber))
                {
                    Dictionary<string, object> dic = masterDic[pointNumber];

                    ModbusSerialMaster master = (ModbusSerialMaster)dic["master"];

                    // 从设备地址
                    byte slaveAddress = (byte)dic["slaveAddress"].ToString().ObjToInt();

                    // 读取起始寄存器地址
                    ushort startAddress = ushort.Parse(dic["startAddress"].ToString());

                    // 读取寄存器数量
                    ushort numberOfPoints = ushort.Parse(dic["numberOfPoints"].ToString());

                    if (count > 1)
                    {
                        numberOfPoints = ushort.Parse(count.ToString());
                    }
                    Task<bool[]> task = master.ReadCoilsAsync(slaveAddress, startAddress, numberOfPoints);
                    try
                    {
                        bool[] shorts = task.Result;
                        return shorts;
                        /*
                        bool fanState = shorts[0];

                        Log.Debug(dic["pointName"] + " 状态：" + fanState);
                        if (key == "RFan" && count > 1)
                        {
                            if (shorts.Length > 1)
                            {
                                fanState = shorts[1];
                                Log.Debug("指示灯状态：" + fanState);
                            }
                        }*/
                    }
                    catch (Exception ex)
                    {
                        Log.Error(dic["pointName"] + " 状态异常：" + ex.Message);
                        return null;
                    }
                }
                else
                {
                    Log.Error(key + " master未创建");
                    return null;
                }
            }
            else
            {
                return null;
            }

        }

        private Dictionary<string, object> ReadInputRegistersAsync(string key)
        {
            if (frormPointDic.ContainsKey(key))
            {
                string pointNumber = frormPointDic[key];

                if (masterDic.ContainsKey(pointNumber))
                {
                    Dictionary<string, object> dic = masterDic[pointNumber];

                    ModbusSerialMaster master = (ModbusSerialMaster)dic["master"];

                    // 从设备地址
                    byte slaveAddress = (byte)dic["slaveAddress"].ToString().ObjToInt();

                    // 读取起始寄存器地址
                    ushort startAddress = ushort.Parse(dic["startAddress"].ToString());

                    // 读取寄存器数量
                    ushort numberOfPoints = ushort.Parse(dic["numberOfPoints"].ToString());
                    Task<ushort[]> task = master.ReadInputRegistersAsync(slaveAddress, startAddress, numberOfPoints);
                    try
                    {
                        ushort[] shorts = task.Result;
                        Dictionary<string, object> back = new Dictionary<string, object>();
                        back["data"] = shorts;
                        back["devicePoint"] = dic["devicePoint"];
                        return back;
                    }
                    catch (Exception ex)
                    {
                        Log.Error(dic["pointName"] + " 温度异常：" + ex.Message);
                        return null;
                    }
                }
                else
                {
                    Log.Error(key + " master未创建");
                    return null;
                }
            }
            else
            {
                Log.Debug(key + " 界面点位未创建");
                return null;
            }
        }

        private bool[] ReadInputsAsync(string key)
        {
            if (frormPointDic.ContainsKey(key))
            {
                string pointNumber = frormPointDic[key];

                if (masterDic.ContainsKey(pointNumber))
                {
                    Dictionary<string, object> dic = masterDic[pointNumber];

                    ModbusSerialMaster master = (ModbusSerialMaster)dic["master"];

                    // 从设备地址
                    byte slaveAddress = (byte)dic["slaveAddress"].ToString().ObjToInt();

                    // 读取起始寄存器地址
                    ushort startAddress = ushort.Parse(dic["startAddress"].ToString());

                    // 读取寄存器数量
                    ushort numberOfPoints = ushort.Parse(dic["numberOfPoints"].ToString());
                    Task<bool[]> task = master.ReadInputsAsync(slaveAddress, startAddress, numberOfPoints);
                    try
                    {
                        bool[] shorts = task.Result;
                        return shorts;
                    }
                    catch (Exception ex)
                    {
                        Log.Error(dic["pointName"] + " 状态获取异常：" + ex.Message);
                        return null;
                    }
                }
                else
                {
                    Log.Debug(key + " master未创建");
                    return null;
                }
            }
            else
            {

                Log.Debug(key + " 界面点位未创建");
                return null;
            }
        }
        private Dictionary<string, object> ReadHoldingRegistersAsync(string key)
        {
            if (frormPointDic.ContainsKey(key))
            {
                string pointNumber = frormPointDic[key];


                if (masterDic.ContainsKey(pointNumber))
                {
                    Dictionary<string, object> dic = masterDic[pointNumber];

                    ModbusSerialMaster master = (ModbusSerialMaster)dic["master"];

                    // 从设备地址
                    byte slaveAddress = (byte)dic["slaveAddress"].ToString().ObjToInt();

                    // 读取起始寄存器地址
                    ushort startAddress = ushort.Parse(dic["startAddress"].ToString());

                    // 读取寄存器数量
                    ushort numberOfPoints = ushort.Parse(dic["numberOfPoints"].ToString());

                    Task<ushort[]> task = master.ReadHoldingRegistersAsync(slaveAddress, startAddress, numberOfPoints);

                    try
                    {
                        ushort[] shorts = task.Result;
                        Dictionary<string, object> back = new Dictionary<string, object>();
                        back["data"] = shorts;
                        back["devicePoint"] = dic["devicePoint"];
                        return back;
                    }
                    catch (Exception ex)
                    {
                        Log.Error(dic["pointName"] + " 结果获取异常：" + ex.Message);
                        return null;
                    }
                }
                else
                {
                    Log.Debug(key + " master未创建");
                    return null;
                }
            }
            else
            {
                Log.Debug(key + " 界面点位未创建");
                return null;
            }
        }

        /// <summary>播报试压结果
        /// 
        /// </summary>
        private void readTestResult(object sender, System.Timers.ElapsedEventArgs e)
        {
            //#主压力值XMp，主温度值X℃，远端压力值XMp，远端温度值X℃
            //string msg = string.Format("主压力值{0}Mp，主温度{1}度，远端压力值{2}Mp，远端温度{3}度", MPressureLabel.Text, MTemperatureInput.Text, RPressureLabel.Text, RTemperatureInput.Text);
            //Broadcast(msg);
        }

        /// <summary>远端压力错误
        /// 
        /// </summary>
        private void RemotPressureError(object sender, System.Timers.ElapsedEventArgs e)
        {
            Broadcast("远端压力值采集失败");
        }

        #endregion

        #region 系统方法
        public IndexForm()
        {
            
            EnableSplashScreen = false;
            WindowState = FormiumWindowState.Maximized;
            Maximizable = false;
            Location = new Point(0,0);
            Sizable = false;
            Screen[] allScreens = Screen.AllScreens;
            Icon icon = new Icon("logo.ico");
            Icon = icon;
            for (int i = 0; i < allScreens.Length; i++)
            {
                Screen screen = allScreens[i];
                if (screen.Primary)
                {
                    MinimumSize = screen.WorkingArea.Size;
                }
            }
            Url = "http://testpressure.app.local/Index.html";
            setup();
            loadDeviceList();
        }

        protected override FormStyle ConfigureWindowStyle(WindowStyleBuilder builder)
        {
            var style = builder.UseSystemForm();
            style.TitleBar = true;
            style.DefaultAppTitle = "试压数据采集";
            return style;
        }

            #endregion
        }
    
    }
